<?php

namespace Dreamcat\PropertyAnalysis\Pojo;

use JetBrains\PhpStorm\Immutable;
use JetBrains\PhpStorm\Pure;
use ReflectionType;

/**
 * 类型描述
 * @author vijay
 */
class TypeDescription
{
    private const PREFIX_STRING = "string::";
    private const PREFIX_CLASS = "class::";


    /** @var OneMayTypeDesc[] 类型可能性 */
    private array $typeDescriptions = [];

    /**
     * @param ?ReflectionType $reflectionType 类型描述反射
     * @param mixed $defaultValue 默认值
     * @param bool $allowNull 是否可以为null
     */
    public function __construct(
        #[Immutable] private ?ReflectionType $reflectionType = null,
        #[Immutable] private mixed $defaultValue = null,
        #[Immutable] private bool $allowNull = true
    ) {
    }

    /**
     * @return ?ReflectionType
     * @codeCoverageIgnore
     */
    #[Pure]
    public function getReflectionType(): ?ReflectionType
    {
        return $this->reflectionType;
    }

    /**
     * @return OneMayTypeDesc[]
     */
    #[Pure]
    public function getTypeDescriptions(): array
    {
        return array_values($this->typeDescriptions);
    }

    /**
     * -
     * @param OneMayTypeDesc $typeDescription
     * @return void
     */
    public function addTypeDescription(OneMayTypeDesc $typeDescription): void
    {
        $type = $typeDescription->getPropertyType();
        if (is_string($type)) {
            $key = self::PREFIX_STRING . $type;
        } else {
            $key = self::PREFIX_CLASS . $type->getName();
        }
        $this->typeDescriptions[$key] = $typeDescription;
    }

    /**
     * 获取类型描述
     * @param string $name 名称
     * @param bool $isClassName 是否类名
     * @return OneMayTypeDesc|null
     * @codeCoverageIgnore
     */
    #[Pure]
    public function getTypeDescription(string $name, bool $isClassName = false): ?OneMayTypeDesc
    {
        if ($isClassName) {
            $key = self::PREFIX_CLASS . $name;
        } else {
            $key = self::PREFIX_STRING . $name;
        }
        return $this->typeDescriptions[$key] ?? null;
    }

    /**
     * @return mixed
     * @codeCoverageIgnore
     */
    #[Pure]
    public function getDefaultValue(): mixed
    {
        return $this->defaultValue;
    }

    /**
     * @return bool
     * @codeCoverageIgnore
     */
    #[Pure]
    public function isAllowNull(): bool
    {
        return $this->allowNull;
    }
}

# end of file
